<!--
 * 厦门大学计算机专业 | 前华为工程师
 * 专注《零基础学编程系列》  http://lblbc.cn/blog
 * 包含：Java | 安卓 | 前端 | Flutter | iOS | 小程序 | 鸿蒙
 * 公众号：蓝不蓝编程
 -->
<template>
	<view class="wrapper">
		<view class="btn btn-mg" @click="startGame">新游戏</view>
		<view>
			<view class="over" v-if="isGameOver">
				<view>游戏结束!</view>
				<view class="btn" @click="startGame">重新开始</view>
			</view>
			<view class="box">
				<view class="row" v-for="row in cellArr">
					<view class="cell" :class="'cell-con-' + col" v-for="col in row">
						{{ col }}
					</view>
				</view>
			</view>
		</view>
	</view>
</template>

<script lang="ts">
	export default {
		data() {
			return {
				cellArr: [] as number[][],
				isGameOver: false
			}
		},
		mounted() {
			this.startGame()
			document.addEventListener('keyup', this.keyDown)
		},
		methods: {
			startGame() {
				this.isGameOver = false
				this.cellArr = [
					[0, 0, 0, 0],
					[0, 0, 0, 0],
					[0, 0, 0, 0],
					[0, 0, 0, 0]
				]
				this.fillOneEmptyCell()
				this.fillOneEmptyCell()
			},
			//找到可以用于生成新数字的单元格，并生成新的数字进行填充
			fillOneEmptyCell() {
				const emptyCells = this.findEmptyCells()
				const index = this.random(emptyCells.length)
				const [row, col] = emptyCells[index]
				this.cellArr[row][col] = this.getRandomValue()
				console.log("fillOneEmptyCell")
			},
			//生成新的数字，90%几率生成2，10%几率生成4
			getRandomValue() : number {
				if (Math.random() < 0.9) {
					return 2
				} else {
					return 4
				}
			},
			//生成随机数，0=<结果<max
			random(max : number) {
				return Math.floor(Math.random() * max)
			},
			findEmptyCells() : [number, number][] {
				const result : [number, number][] = []
				for (let i = 0; i < 4; i++) {
					for (let j = 0; j < 4; j++) {
						if (this.cellArr[i][j] === 0) {
							result.push([i, j])
						}
					}
				}
				return result
			},
			move(direction : string) {
				this.moveCells(direction)
				this.checkGameOverOrContinue()
			},
			moveCells(direction : string) {
				const isHorizontal = direction === 'left' || direction === 'right'
				const isForward = direction === 'left' || direction === 'up'

				for (let i = 0; i < 4; i++) {
					let cells : number[] = []
					if (isHorizontal) {
						cells = this.cellArr[i]
					} else {
						for (let j = 0; j < 4; j++) {
							cells.push(this.cellArr[j][i])
						}
					}
					const result = this.removeZerosAndAdd(cells, isForward)
					if (isHorizontal) {
						this.cellArr[i] = result
					} else {
						result.forEach((value, j) => (this.cellArr[j][i] = value))
					}
				}
			},
			removeZerosAndAdd(cells : number[], isForward : boolean) : number[] {
				const nonZeroCells = cells.filter(x => x !== 0)
				const mergedCells = this.mergeCells(nonZeroCells, isForward)
				const result = [0, 0, 0, 0]
				if (isForward) {
					result.splice(0, mergedCells.length, ...mergedCells)
				} else {
					result.splice(4 - mergedCells.length, mergedCells.length, ...mergedCells)
				}
				return result
			},
			mergeCells(cells : number[], isForward : boolean) : number[] {
				if (!isForward) {
					cells = cells.reverse()
				}
				let result : number[] = []
				let i = 0
				while (i < cells.length) {
					if (i < cells.length - 1 && cells[i] === cells[i + 1]) {
						result.push(cells[i] * 2)
						i += 2
					} else {
						result.push(cells[i])
						i += 1
					}
				}
				if (!isForward) {
					result = result.reverse()
				}
				return result
			},
			checkGameOverOrContinue() {
				if (this.canMove()) {
					this.fillOneEmptyCell()
				} else {
					this.isGameOver = true
				}
			},
			canMove() : boolean {
				const cellArr = this.cellArr
				for (let i = 0; i < 4; i++) {
					for (let j = 0; j < 4; j++) {
						if (cellArr[i][j] === 0) {
							return true
						}
						if (j < 3 && cellArr[i][j] === cellArr[i][j + 1]) {
							return true
						}
						if (i < 3 && cellArr[i][j] === cellArr[i + 1][j]) {
							return true
						}
					}
				}
				return false
			},
			//键盘监听事件
			keyDown(e) {
				let arr = null
				switch (e.keyCode) {
					case 38: //上
						this.move('up')
						break
					case 40: //下
						this.move('down')
						break
					case 37: //左
						this.move('left')
						break
					case 39: //右
						this.move('right')
						break
				}
			},
		}
	}
</script>

<style scoped>
	.wrapper {
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
	}

	.box {
		display: flex;
		flex-direction: column;
		background: #C1B09D;
		width: 350px;
		height: 350px;
		border-radius: 5px;
	}

	.row {
		display: flex;
		flex-direction: row;
	}

	.cell {
		width: 76px;
		height: 76px;
		background: #CDC1B4;
		justify-content: center;
		align-items: center;
		display: flex;
		margin: 6px;
		font-size: 35px;
		font-weight: bold;
		border-radius: 5px;
	}

	.cell-con-0 {
		color: transparent
	}

	.cell-con-2 {
		background: #eee4da;
	}

	.cell-con-4 {
		background: #ede0c8;
	}

	.cell-con-8 {
		color: white;
		background: #f2b179;
	}

	.cell-con-16 {
		color: white;
		background: #f2b179;
	}

	.cell-con-32 {
		color: white;
		background: #f67c5f;
	}

	.cell-con-64 {
		color: white;
		background: #f65e3b;
	}

	.cell-con-128 {
		color: white;
		background: #edcf72;
		font-size: 30px;
	}

	.cell-con-256 {
		color: white;
		font-size: 30px;
		background: #edcc61;
	}

	.cell-con-512 {
		color: white;
		font-size: 30px;
		background: #edc850;
	}

	.cell-con-1024 {
		color: white;
		font-size: 25px;
		background: #edc53f;
	}

	.cell-con-2048 {
		color: white;
		font-size: 25px;
		background: #edc22e;
	}

	.over {
		background: #eee4dacc;
		color: #8f7a66;
		width: 350px;
		height: 350px;
		position: absolute;
		z-index: 1000;
		display: flex;
		justify-content: center;
		align-items: center;
		flex-direction: column;
	}

	.btn {
		background: #8f7a66;
		color: #f9f6f2;
		height: 40px;
		display: flex;
		justify-content: center;
		align-items: center;
		padding: 0 20px;
		border-radius: 5px;
	}

	.btn-mg {
		margin-bottom: 10px;
	}
</style>